#include <stdint.h>
#include <stddef.h>

#include "driver_gpio.h"
#include "fr30xx.h"
#include "app_task.h"
#include "fr_device_pmu_io.h"
#include "fr_device_button.h"
#include "app_lvgl.h"

/* FreeRTOS kernel includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "timers.h"



#define BUTTON_IDX_MAX              1

#define BUTTON_SHORT_DURING             0x08        // x10ms
#define BUTTON_LONG_DURING              0x14        // x100ms
#define BUTTON_LONG_LONG_DURING         0x28        // x100ms
#define BUTTON_MULTI_INTERVAL           0x14        // x10ms
#define BUTTON_LONG_PRESSING_INTERVAL   0x1e        // x10ms

uint8_t current_state = BUTTON_WORKING_STATE_IDLE;
uint16_t button_task_id;
xTimerHandle button_anti_shake_timer;
xTimerHandle button_pressing_timer;
xTimerHandle button_state_timer;

/* which io is enabled for button function */
uint32_t button_io_mask = 0;
uint32_t curr_button_before_anti_shake = 0;
uint32_t current_pressed_button = 0;
uint32_t last_saved_button = 0;
uint32_t button_to_be_send = 0;     //for multi click
uint8_t pressed_cnt = 0;           //for multi click

void button_toggle_detected(uint32_t curr_button)
{
    if(button_io_mask != 0) {
        curr_button_before_anti_shake = curr_button & button_io_mask;
        if(xPortIsInsideInterrupt()) 
            xTimerStartFromISR( button_anti_shake_timer, NULL );
        else
            xTimerStart(button_anti_shake_timer, 0);
        
    }
}

void button_int_isr(uint32_t changed_button)
{
    uint32_t curr_button;

    curr_button = current_pressed_button ^ changed_button;

	struct app_task_event *event;
	event = app_task_event_alloc(APP_TASK_EVENT_BTN_TOGGLE, sizeof(uint32_t), false);
	if(event) 
	{
		memcpy(event->param, (void *)&curr_button, sizeof(uint32_t));
		event->param_len = sizeof(uint32_t);
		app_task_event_post(event, false);
	}

}

void button_send_event(uint8_t event, uint32_t button, uint8_t cnt)
{
    struct button_msg_t msg;

    msg.button_index = button;
    msg.button_type = event;
    msg.button_cnt = cnt;

	struct app_task_event *toggle_event;
	toggle_event = app_task_event_alloc(APP_TASK_EVENT_BTN_OUTPUT, sizeof(msg), false);
	if(toggle_event) 
	{
		memcpy(toggle_event->param, (void *)&msg, sizeof(msg));
		toggle_event->param_len = sizeof(msg);
		app_task_event_post(toggle_event, false);
	}

    pressed_cnt = 0;
}

static void button_idle(uint8_t event)
{
    if(event == BUTTON_WORKING_EVENT_SINGLE_PRESSED)
    {
        current_state = BUTTON_WORKING_STATE_JUST_PRESSED;
        xTimerChangePeriod(button_state_timer, BUTTON_SHORT_DURING*10,0);
        xTimerStart(button_state_timer,0);
        button_send_event(BUTTON_PRESSED, current_pressed_button, pressed_cnt);
    }
    else if(event == BUTTON_WORKING_EVENT_COMB_PRESSED)
    {
        current_state = BUTTON_WORKING_STATE_COMB_JUST_PRESSED;
        xTimerChangePeriod(button_state_timer, BUTTON_SHORT_DURING*10,0);
        xTimerStart(button_state_timer,0);
        button_send_event(BUTTON_COMB_PRESSED, current_pressed_button, pressed_cnt);
    }
}

static void button_just_pressed(uint8_t event)
{
    if(event == BUTTON_WORKING_EVENT_RELEASED)
    {
        current_state = BUTTON_WORKING_STATE_IDLE;
        xTimerStop(button_state_timer,0);
        button_send_event(BUTTON_RELEASED, last_saved_button, pressed_cnt);
    }
    else if(event == BUTTON_WORKING_EVENT_COMB_PRESSED)
    {
        current_state = BUTTON_WORKING_STATE_COMB_JUST_PRESSED;
        xTimerChangePeriod(button_state_timer, BUTTON_SHORT_DURING*10,0);
        xTimerStart(button_state_timer,0);
        button_send_event(BUTTON_COMB_PRESSED, current_pressed_button, pressed_cnt);
    }
    else if(event == BUTTON_WORKING_EVENT_TIME_OUT)
    {
        current_state = BUTTON_WORKING_STATE_PRESSED;
        xTimerChangePeriod(button_state_timer, (BUTTON_LONG_DURING*10-BUTTON_SHORT_DURING)*10,0);
        xTimerStart(button_state_timer,0);
    }
}

static void button_pressed(uint8_t event)
{
    if(event == BUTTON_WORKING_EVENT_RELEASED)
    {
        if(0/*__jump_table.button_disable_multi_click*/ & last_saved_button)
        {
            current_state = BUTTON_WORKING_STATE_IDLE;
            button_send_event(BUTTON_SHORT_PRESSED, last_saved_button, 0);
        }
        else
        {
            //TBD锟斤拷锟角凤拷锟斤拷锟斤拷锟斤拷锟斤拷锟�
            current_state = BUTTON_WORKING_STATE_WAIT_MULTI;
            button_to_be_send = last_saved_button;
            pressed_cnt++;
            xTimerChangePeriod(button_state_timer,BUTTON_MULTI_INTERVAL*10,0);
            xTimerStart(button_state_timer,0);
        }
    }
    else if(event == BUTTON_WORKING_EVENT_COMB_PRESSED)
    {
        current_state = BUTTON_WORKING_STATE_COMB_JUST_PRESSED;
        xTimerChangePeriod(button_state_timer, BUTTON_SHORT_DURING*10,0);
        xTimerStart(button_state_timer,0);
        button_send_event(BUTTON_COMB_PRESSED, current_pressed_button, pressed_cnt);
    }
    else if(event == BUTTON_WORKING_EVENT_TIME_OUT)
    {
        current_state = BUTTON_WORKING_STATE_LONG_PRESSED;
        xTimerChangePeriod(button_state_timer, ((BUTTON_LONG_LONG_DURING-BUTTON_LONG_DURING)*10)*10,0);
        xTimerStart(button_state_timer,0);
        xTimerChangePeriod(button_pressing_timer, BUTTON_LONG_PRESSING_INTERVAL*10,0);
        xTimerStart(button_pressing_timer,0);
        button_send_event(BUTTON_LONG_PRESSED, current_pressed_button, pressed_cnt);
    }
}

static void button_wait_multi(uint8_t event)
{
    if(event == BUTTON_WORKING_EVENT_SINGLE_PRESSED)
    {
        if(current_pressed_button != button_to_be_send)
        {
            if(pressed_cnt > 1)
            {
                button_send_event(BUTTON_MULTI_PRESSED, button_to_be_send, pressed_cnt);
            }
            else
            {
                button_send_event(BUTTON_SHORT_PRESSED, button_to_be_send, pressed_cnt);
            }
            button_send_event(BUTTON_PRESSED, current_pressed_button, pressed_cnt);
        }
        current_state = BUTTON_WORKING_STATE_JUST_PRESSED;
        xTimerChangePeriod(button_state_timer, BUTTON_SHORT_DURING*10,0);
        xTimerStart(button_state_timer,0);
    }
    else if(event == BUTTON_WORKING_EVENT_COMB_PRESSED)
    {
        current_state = BUTTON_WORKING_STATE_COMB_JUST_PRESSED;
        xTimerChangePeriod(button_state_timer, BUTTON_SHORT_DURING*10,0);
        xTimerStart(button_state_timer,0);
        button_send_event(BUTTON_COMB_PRESSED, current_pressed_button, pressed_cnt);
        button_send_event(BUTTON_SHORT_PRESSED, button_to_be_send, pressed_cnt);
    }
    else if(event == BUTTON_WORKING_EVENT_TIME_OUT)
    {
        current_state = BUTTON_WORKING_STATE_IDLE;
        if(pressed_cnt > 1)
        {
            button_send_event(BUTTON_MULTI_PRESSED, button_to_be_send, pressed_cnt);
        }
        else
        {
            button_send_event(BUTTON_SHORT_PRESSED, button_to_be_send, pressed_cnt);
        }
    }
}

static void button_long_pressed(uint8_t event)
{
    if(event == BUTTON_WORKING_EVENT_RELEASED)
    {
        current_state = BUTTON_WORKING_STATE_IDLE;
        xTimerStop(button_state_timer,0);
        xTimerStop(button_pressing_timer,0);
        button_send_event(BUTTON_LONG_RELEASED, last_saved_button, pressed_cnt);
    }
    else if(event == BUTTON_WORKING_EVENT_COMB_PRESSED)
    {
        current_state = BUTTON_WORKING_STATE_COMB_JUST_PRESSED;
        xTimerChangePeriod(button_state_timer, BUTTON_SHORT_DURING*10,0);
        xTimerStart(button_state_timer,0);
        xTimerStop(button_pressing_timer,0);
        button_send_event(BUTTON_COMB_PRESSED, current_pressed_button, pressed_cnt);
        button_send_event(BUTTON_LONG_RELEASED, last_saved_button, pressed_cnt);
    }
    else if(event == BUTTON_WORKING_EVENT_TIME_OUT)
    {
        current_state = BUTTON_WORKING_STATE_LONG_LONG_PRESSED;
        button_send_event(BUTTON_LONG_LONG_PRESSED, current_pressed_button, pressed_cnt);
    }
}

static void button_long_long_pressed(uint8_t event)
{
    if(event == BUTTON_WORKING_EVENT_RELEASED)
    {
        xTimerStop(button_pressing_timer,0);
        current_state = BUTTON_WORKING_STATE_IDLE;
        button_send_event(BUTTON_LONG_LONG_RELEASED, last_saved_button, pressed_cnt);
    }
    else if(event == BUTTON_WORKING_EVENT_COMB_PRESSED)
    {
        current_state = BUTTON_WORKING_STATE_COMB_JUST_PRESSED;
        xTimerChangePeriod(button_state_timer, BUTTON_SHORT_DURING*10,0);
        xTimerStart(button_state_timer,0);
        xTimerStop(button_pressing_timer,0);
        button_send_event(BUTTON_COMB_PRESSED, current_pressed_button, pressed_cnt);
        button_send_event(BUTTON_LONG_LONG_RELEASED, last_saved_button, pressed_cnt);
    }
}

static void button_comb_just_pressed(uint8_t event)
{
    if(event == BUTTON_WORKING_EVENT_RELEASED)
    {
        current_state = BUTTON_WORKING_STATE_IDLE;
        xTimerStop(button_state_timer,0);
        button_send_event(BUTTON_COMB_RELEASED, last_saved_button, pressed_cnt);
    }
    else if(event == BUTTON_WORKING_EVENT_SINGLE_PRESSED)
    {
        current_state = BUTTON_WORKING_STATE_JUST_PRESSED;
        xTimerChangePeriod(button_state_timer, BUTTON_SHORT_DURING*10,0);
        xTimerStart(button_state_timer,0);
        button_send_event(BUTTON_COMB_RELEASED, last_saved_button, pressed_cnt);
        button_send_event(BUTTON_PRESSED, current_pressed_button, pressed_cnt);
    }
    else if(event == BUTTON_WORKING_EVENT_COMB_PRESSED)
    {
        current_state = BUTTON_WORKING_STATE_JUST_PRESSED;
        xTimerChangePeriod(button_state_timer, BUTTON_SHORT_DURING*10,0);
        xTimerStart(button_state_timer,0);
        button_send_event(BUTTON_COMB_PRESSED, current_pressed_button, pressed_cnt);
    }
    else if(event == BUTTON_WORKING_EVENT_TIME_OUT)
    {
        current_state = BUTTON_WORKING_STATE_COMB_PRESSED;
        xTimerChangePeriod(button_state_timer, (BUTTON_LONG_DURING*10-BUTTON_SHORT_DURING)*10,0);
        xTimerStart(button_state_timer,0);
    }
}

static void button_comb_pressed(uint8_t event)
{
    if(event == BUTTON_WORKING_EVENT_RELEASED)
    {
        current_state = BUTTON_WORKING_STATE_IDLE;
        xTimerStop(button_state_timer,0);
        button_send_event(BUTTON_COMB_SHORT_PRESSED, last_saved_button, pressed_cnt);
    }
    else if(event == BUTTON_WORKING_EVENT_SINGLE_PRESSED)
    {
        current_state = BUTTON_WORKING_STATE_JUST_PRESSED;
        xTimerChangePeriod(button_state_timer, BUTTON_SHORT_DURING*10,0);
        xTimerStart(button_state_timer,0);
        button_send_event(BUTTON_COMB_SHORT_PRESSED, last_saved_button, pressed_cnt);
        button_send_event(BUTTON_PRESSED, current_pressed_button, pressed_cnt);
    }
    else if(event == BUTTON_WORKING_EVENT_COMB_PRESSED)
    {
        current_state = BUTTON_WORKING_STATE_COMB_JUST_PRESSED;
        xTimerChangePeriod(button_state_timer, BUTTON_SHORT_DURING*10,0);
        xTimerStart(button_state_timer,0);
        button_send_event(BUTTON_COMB_SHORT_PRESSED, last_saved_button, pressed_cnt);
        button_send_event(BUTTON_COMB_PRESSED, current_pressed_button, pressed_cnt);
    }
    else if(event == BUTTON_WORKING_EVENT_TIME_OUT)
    {
        current_state = BUTTON_WORKING_STATE_COMB_LONG_PRESSED;
        xTimerChangePeriod(button_state_timer, ((BUTTON_LONG_LONG_DURING-BUTTON_LONG_DURING)*10)*10,0);
        xTimerStart(button_state_timer,0);

        xTimerChangePeriod(button_pressing_timer, BUTTON_LONG_PRESSING_INTERVAL*10,0);
        xTimerStart(button_pressing_timer,0);
        button_send_event(BUTTON_COMB_LONG_PRESSED, current_pressed_button, pressed_cnt);
    }
}

static void button_comb_long_pressed(uint8_t event)
{
    if(event == BUTTON_WORKING_EVENT_RELEASED)
    {
        current_state = BUTTON_WORKING_STATE_IDLE;
        xTimerStop(button_state_timer,0);

        xTimerStop(button_pressing_timer,0);
        button_send_event(BUTTON_COMB_LONG_RELEASED, last_saved_button, pressed_cnt);
    }
    else if(event == BUTTON_WORKING_EVENT_SINGLE_PRESSED)
    {
        current_state = BUTTON_WORKING_STATE_JUST_PRESSED;
        xTimerChangePeriod(button_state_timer, BUTTON_SHORT_DURING*10,0);
        xTimerStart(button_state_timer,0);
        xTimerStop(button_pressing_timer,0);
        button_send_event(BUTTON_COMB_LONG_RELEASED, last_saved_button, pressed_cnt);
        button_send_event(BUTTON_PRESSED, current_pressed_button, pressed_cnt);
    }
    else if(event == BUTTON_WORKING_EVENT_COMB_PRESSED)
    {
        current_state = BUTTON_WORKING_STATE_COMB_JUST_PRESSED;
        xTimerChangePeriod(button_state_timer, BUTTON_SHORT_DURING*10,0);
        xTimerStart(button_state_timer,0);
        xTimerStop(button_pressing_timer,0);
        button_send_event(BUTTON_COMB_LONG_RELEASED, last_saved_button, pressed_cnt);
        button_send_event(BUTTON_COMB_PRESSED, current_pressed_button, pressed_cnt);
    }
    else if(event == BUTTON_WORKING_EVENT_TIME_OUT)
    {
        current_state = BUTTON_WORKING_STATE_COMB_LONG_LONG_PRESSED;
        button_send_event(BUTTON_COMB_LONG_LONG_PRESSED, current_pressed_button, pressed_cnt);
    }
}

static void button_comb_long_long_pressed(uint8_t event)
{
    if(event == BUTTON_WORKING_EVENT_RELEASED)
    {
        current_state = BUTTON_WORKING_STATE_IDLE;
        xTimerStop(button_pressing_timer,0);
        button_send_event(BUTTON_COMB_LONG_LONG_RELEASED, last_saved_button, pressed_cnt);
    }
    else if(event == BUTTON_WORKING_EVENT_SINGLE_PRESSED)
    {
        current_state = BUTTON_WORKING_STATE_JUST_PRESSED;
        xTimerChangePeriod(button_state_timer, BUTTON_SHORT_DURING*10,0);
        xTimerStart(button_state_timer,0);
        xTimerStop(button_pressing_timer,0);
        button_send_event(BUTTON_COMB_LONG_LONG_RELEASED, last_saved_button, pressed_cnt);
        button_send_event(BUTTON_PRESSED, current_pressed_button, pressed_cnt);
    }
    else if(event == BUTTON_WORKING_EVENT_COMB_PRESSED)
    {
        current_state = BUTTON_WORKING_STATE_COMB_JUST_PRESSED;
        xTimerChangePeriod(button_state_timer, BUTTON_SHORT_DURING*10,0);
        xTimerStart(button_state_timer,0);
        xTimerStop(button_pressing_timer,0);
        button_send_event(BUTTON_COMB_LONG_LONG_RELEASED, last_saved_button, pressed_cnt);
        button_send_event(BUTTON_COMB_PRESSED, current_pressed_button, pressed_cnt);
    }
}

void (*const button_statemachines[BUTTON_WORKING_STATE_MAX])(uint8_t) =
{
    button_idle,
    button_just_pressed,
    button_pressed,
    button_wait_multi,
    button_long_pressed,
    button_long_long_pressed,
    button_comb_just_pressed,
    button_comb_pressed,
    button_comb_long_pressed,
    button_comb_long_long_pressed,
};

//one or more button is released or pressed
int button_toggle_handler(uint32_t curr_button)
{
    enum button_working_event_t event;

    current_pressed_button = curr_button;

    if(last_saved_button != current_pressed_button)
    {
        if(current_pressed_button == 0)
        {
            event = BUTTON_WORKING_EVENT_RELEASED;
        }
        else
        {
            if((current_pressed_button & (current_pressed_button-1)) == 0)
            {
                event = BUTTON_WORKING_EVENT_SINGLE_PRESSED;
            }
            else
            {
                event = BUTTON_WORKING_EVENT_COMB_PRESSED;
            }
        }

        button_statemachines[current_state](event);

        last_saved_button = current_pressed_button;
    }

    return 0;
}

static void button_timeout_handler( TimerHandle_t xTimer)
{
    button_statemachines[current_state](BUTTON_WORKING_EVENT_TIME_OUT);
}

static void button_pressing_timeout_handler( TimerHandle_t xTimer )
{
    enum button_type_t event;
    if((current_pressed_button & (current_pressed_button - 1)) == 0)
    {
        event = BUTTON_LONG_PRESSING;
    }
    else
    {
        event = BUTTON_COMB_LONG_PRESSING;
    }

    button_send_event(event, current_pressed_button, pressed_cnt);

    xTimerChangePeriod(button_pressing_timer, BUTTON_LONG_PRESSING_INTERVAL*10,0);
    xTimerStart(button_pressing_timer,0);
}

static void button_anti_shake_timeout_handler( TimerHandle_t xTimer )
{
    uint32_t curr_button;

    curr_button = ool_read16(PMU_REG_PIN_DATA);
    curr_button &= button_io_mask;

    if(curr_button == curr_button_before_anti_shake)
    {
        curr_button ^= button_io_mask;

		struct app_task_event *event;
		event = app_task_event_alloc(APP_TASK_EVENT_BTN_TOGGLE, sizeof(uint32_t), false);
		if(event) 
		{
			memcpy(event->param, (void *)&curr_button, sizeof(uint32_t));
			event->param_len = sizeof(uint32_t);
			app_task_event_post(event, false);
		}
    }
}

void button_event_handler(void * param)
{
	struct button_msg_t *button_msg;
	const char *button_type_str[] = {
										"BUTTON_PRESSED",
										"BUTTON_RELEASED",
										"BUTTON_SHORT_PRESSED",
										"BUTTON_MULTI_PRESSED",
										"BUTTON_LONG_PRESSED",
										"BUTTON_LONG_PRESSING",
										"BUTTON_LONG_RELEASED",
										"BUTTON_LONG_LONG_PRESSED",
										"BUTTON_LONG_LONG_RELEASED",
										"BUTTON_COMB_PRESSED",
										"BUTTON_COMB_RELEASED",
										"BUTTON_COMB_SHORT_PRESSED",
										"BUTTON_COMB_LONG_PRESSED",
										"BUTTON_COMB_LONG_PRESSING",
										"BUTTON_COMB_LONG_RELEASED",
										"BUTTON_COMB_LONG_LONG_PRESSED",
										"BUTTON_COMB_LONG_LONG_RELEASED",
									};

	button_msg = (struct button_msg_t *)param;
	
	printf("KEY 0x%08x, TYPE %s. %d\r\n", button_msg->button_index, button_type_str[button_msg->button_type],button_msg->button_type);
             
    if(button_msg->button_type == BUTTON_SHORT_PRESSED) //short button
    {

        #if BOARD_SEL == BOARD_EVB_FR5090
            if(button_msg->button_index == BUTTON_PIN_NUM)
            {
                if(!gui_task_resume())
                {
                    gui_task_msg_send(BUTTON_KEY5_EVT,NULL,0,NULL,0,NULL);
                }
            }
            else if(button_msg->button_index == SOS_KEY_PIN_NUM)
            {
                if(!gui_task_resume())
                {
                    gui_task_msg_send(BUTTON_KEY3_EVT,NULL,0,NULL,0,NULL);
                }
            }
            else if(button_msg->button_index == KEY1_PIN_NUM)
            {
                if(!gui_task_resume())
                {
                    gui_task_msg_send(BUTTON_KEY1_EVT,NULL,0,NULL,0,NULL);
                }
            }
            else if(button_msg->button_index == KEY2_PIN_NUM)
            {
                if(!gui_task_resume())
                {
                    gui_task_msg_send(BUTTON_KEY4_EVT,NULL,0,NULL,0,NULL);
                }
            }
        #elif BOARD_SEL == BOARD_EVB_FR3092E_RGB

            #if BOARD_VERSION == BOARD_V1_0
                if(button_msg->button_index == BUTTON_PIN_NUM)
                {
                    if(!gui_task_resume())
                    {
                        gui_task_msg_send(BUTTON_KEY5_EVT,NULL,0,NULL,0,NULL);
                    }
                }
                else if(button_msg->button_index == SOS_KEY_PIN_NUM)
                {
                    if(!gui_task_resume())
                    {
                        gui_task_msg_send(BUTTON_KEY3_EVT,NULL,0,NULL,0,NULL);
                    }
                }
                else if(button_msg->button_index == KEY1_PIN_NUM)
                {
                    if(!gui_task_resume())
                    {
                        gui_task_msg_send(BUTTON_KEY1_EVT,NULL,0,NULL,0,NULL);
                    }
                }
                else if(button_msg->button_index == KEY2_PIN_NUM)
                {
                    if(!gui_task_resume())
                    {
                        gui_task_msg_send(BUTTON_KEY4_EVT,NULL,0,NULL,0,NULL);
                    }
                }
            #elif BOARD_VERSION == BOARD_V1_3
                if(button_msg->button_index == BUTTON_PIN_NUM)
                {
                    if(!gui_task_resume())
                    {
                        gui_task_msg_send(BUTTON_KEY5_EVT,NULL,0,NULL,0,NULL);
                    }
                }
                else if(button_msg->button_index == KEY1_PIN_NUM)
                {
                    if(!gui_task_resume())
                    {
                        gui_task_msg_send(BUTTON_KEY3_EVT,NULL,0,NULL,0,NULL);
                    }
                }
                else if(button_msg->button_index == KEY2_PIN_NUM)
                {
                    if(!gui_task_resume())
                    {
                        gui_task_msg_send(BUTTON_KEY4_EVT,NULL,0,NULL,0,NULL);
                    }
                }
            #else
            #error "choose correct board"
            #endif

        #else
        #error "choose correct board"
        #endif  

    }
	else if(button_msg->button_type == BUTTON_LONG_PRESSED)//long
    {
        if(button_msg->button_index == BUTTON_PIN_NUM)
        {

        }
        // else if(button_msg->button_index == SOS_KEY_PIN_NUM)
        // {
            
        // }
	}
}

void button_init(uint32_t enable_io)
{
    button_io_mask = enable_io;
    
    button_anti_shake_timer = xTimerCreate("button_anti_shake_timer", 10, pdFALSE, NULL, button_anti_shake_timeout_handler);
    button_pressing_timer = xTimerCreate("button_pressing_timer", BUTTON_LONG_PRESSING_INTERVAL * 10, pdFALSE, NULL, button_pressing_timeout_handler);
    button_state_timer = xTimerCreate("button_state_timer",  10 , pdFALSE, NULL, button_timeout_handler);

}

